using System;
using System.Collections.Generic;
using System.Linq;
using Behaviorize.TextFormatting;

namespace Behaviorize.Reporting.Model
{
	internal class Report : INamespaceAndFeatureContainer
	{
		public string Assembly { get; set; }
		public string LastUpdate { get; set; }
		public List<Feature> Features { get; set; }
		public List<Namespace> Namespaces { get; set; }

		public Report()
		{
			Namespaces = new List<Namespace>();
			Features = new List<Feature>();
		}

		/// <exception cref="FeatureNotDeclaredException">Raised if the containing feature is not added to the report</exception>
		public void CreateScenarioReport(Behaviorize.Feature testFeature, string scenarioName, List<Behaviorize.ScenarioVersion> testScenarios)
		{
			INamespaceAndFeatureContainer container = GetFeatureContainer(testFeature.Namespace);
			Feature feature = container.Features.SingleOrDefault(f => f.Name == testFeature.Name);

			if (feature == null)
			{
				throw new FeatureNotDeclaredException("A feature must be declared");
			}

			feature.CreateOrUpdateScenario(scenarioName, testScenarios);
		}

		private INamespaceAndFeatureContainer GetFeatureContainer(string name)
		{
			if (string.IsNullOrEmpty(name)) return this;

			string[] namespaces = name.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
			INamespaceAndFeatureContainer container = this;

			foreach (string nsName in namespaces)
			{
				Namespace ns = container.Namespaces.SingleOrDefault(n => n.Name == nsName);

				if (ns == null)
				{
					ns = new Namespace
						{
							Name = nsName
						};

					container.Namespaces.Add(ns);
				}

				container = ns;
			}

			return container;
		}

		public void CreateFeature(Behaviorize.Feature testFeature)
		{
			INamespaceAndFeatureContainer container = GetFeatureContainer(testFeature.Namespace);
			Feature feature = container.Features.SingleOrDefault(f => f.Name == testFeature.Name);

			if (feature == null)
			{
				feature = new Feature
					{
						Scenarios = new List<Scenario>()
					};

				container.Features.Add(feature);
			}
			
			feature.ClassName = PascalFormatter.ToPascalCase(testFeature.Name);
			feature.Description = testFeature.Description;
			feature.Name = testFeature.Name;
			feature.LastRun = DateTime.Now.ToString();

			if (testFeature.UserStory != null)
			{
				feature.UserStory = string.Format("As a {0},\r\nI want {1}\r\nso that {2}",
				                                  testFeature.UserStory.Role,
				                                  testFeature.UserStory.Goal,
				                                  testFeature.UserStory.Motivation);
			}

			LastUpdate = feature.LastRun;
		}
	}
}